package com.app.business.utils;

import com.aliyun.oss.OSS;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.common.utils.IOUtils;
import com.aliyun.oss.model.*;
import com.app.business.config.oss.OssClientFactory;
import com.app.system.utils.dataType.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.*;

/**
 * oss操作工具类
 *
 * @author WMY
 */
//@Component
public class OSSClientUtil {

    protected static final Logger log = LoggerFactory.getLogger(OSSClientUtil.class);

    @Value("${Oos.bucketName}")
    private String bucketName;
    @Value("${Oos.uploadPre}")
    private String uploadPre;
    @Value("${Oos.viewPre}")
    private String viewPre;
    @Value("${Oos.imgHandleStyle}")
    private String imgHandleStyle;

    /**
     * 上传图片
     * 自定义名称
     *
     * @param file
     * @return
     */
    private String uploadImg2Oss(MultipartFile file, String uploadFilePath, String uploadFileName) {
        if (file.getSize() > 1024 * 1024 * 20) {
            // RestResultGenerator.createErrorResult(ResponseEnum.PHOTO_TOO_MAX);
            return "图片太大";
        }
        String originalFilename = file.getOriginalFilename();
        String suffix = originalFilename.substring(originalFilename.lastIndexOf(".")).toLowerCase();
        uploadFileName = uploadFileName + suffix;
        try {
            InputStream inputStream = file.getInputStream();
            String etag = this.uploadFile2OSS(inputStream, uploadFilePath, uploadFileName);
            System.out.println("*************etag:   " + etag);
            // RestResultGenerator.createSuccessResult(name);
            return uploadFileName;
        } catch (Exception e) {
            // RestResultGenerator.createErrorResult(ResponseEnum.PHOTO_UPLOAD);
            return "上传失败";
        }
    }

    /**
     * 上传图片并处理图片生成不同规格图片
     * 自定义名称
     *
     * @param file
     * @return
     */
    private String uploadImg2OssAndHandleImg(MultipartFile file, String uploadFilePath, String uploadFileName) {
        if (file.getSize() > 1024 * 1024 * 20) {
            // RestResultGenerator.createErrorResult(ResponseEnum.PHOTO_TOO_MAX);
            return "图片太大";
        }
        String originalFilename = file.getOriginalFilename();
        String suffix = originalFilename.substring(originalFilename.lastIndexOf(".")).toLowerCase();
        uploadFileName = uploadFileName + suffix;
        try {
            InputStream inputStream = file.getInputStream();
            String etag = this.uploadFile2OSSAndHandleImg(inputStream, uploadFilePath, uploadFileName);
            System.out.println("*************etag:   " + etag);
            // RestResultGenerator.createSuccessResult(name);
            return uploadFileName;
        } catch (Exception e) {
            // RestResultGenerator.createErrorResult(ResponseEnum.PHOTO_UPLOAD);
            return "上传失败";
        }
    }

    /**
     * 上传图片获取etag
     *
     * @param instream
     * @param fileName
     * @return
     */
    private String uploadFile2OSS(InputStream instream, String uploadFilePath, String fileName) {
        String ret = "";
        try {
            //创建上传Object的Metadata
            ObjectMetadata objectMetadata = new ObjectMetadata();
            objectMetadata.setContentLength(instream.available());
            objectMetadata.setCacheControl("no-cache");
            objectMetadata.setHeader("Pragma", "no-cache");
            objectMetadata.setContentType(this.getContentType(fileName.substring(fileName.lastIndexOf("."))));
            objectMetadata.setContentDisposition("inline;filename=" + fileName);

            OSS ossClient = OssClientFactory.getOssClient();
            PutObjectResult putResult = ossClient.putObject(bucketName, uploadFilePath + fileName, instream, objectMetadata);
            ret = putResult.getETag();
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        } finally {
            try {
                if (instream != null) {
                    instream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return ret;
    }

    /**
     * 上传图片并处理为各宽度图并获取etag
     *
     * @param instream
     * @param fileName
     * @return
     */
    private String uploadFile2OSSAndHandleImg(InputStream instream, String uploadFilePath, String fileName) {
        String ret = "";
        try {
            //创建上传Object的Metadata
            ObjectMetadata objectMetadata = new ObjectMetadata();
            objectMetadata.setContentLength(instream.available());
            objectMetadata.setCacheControl("no-cache");
            objectMetadata.setHeader("Pragma", "no-cache");
            objectMetadata.setContentType(this.getContentType(fileName.substring(fileName.lastIndexOf("."))));
            objectMetadata.setContentDisposition("inline;filename=" + fileName);

            OSS ossClient = OssClientFactory.getOssClient();
            PutObjectResult putResult = ossClient.putObject(bucketName, uploadFilePath + fileName, instream, objectMetadata);
            ret = putResult.getETag();

            this.handleImgForStyle(ossClient, uploadFilePath, fileName);
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        } finally {
            try {
                if (instream != null) {
                    instream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return ret;
    }

    /**
     * 处理图片，将其按几种样式处理，并储存到原图所在bucket
     *
     * @param ossClient
     * @param uploadFilePath
     * @param fileName
     */
    private void handleImgForStyle(OSS ossClient, String uploadFilePath, String fileName) {
        if (imgHandleStyle != null) {
            // 原图完整路径
            String sourceImage = uploadFilePath + fileName;
            // 原图名称（不带后缀名）
            String sourceNamePre = fileName.substring(0, fileName.lastIndexOf("."));
            // 原图后缀名
            String sourceNameSuf = fileName.substring(fileName.lastIndexOf("."));
            // 需要删除图片列表
            ArrayList<String> deleteObjectList = new ArrayList<>();

            String[] imgStyleStrings = imgHandleStyle.split(",");
            for (String imgHandleStyle : imgStyleStrings) {
                // 结果图片宽度
                String width = imgHandleStyle.split("-")[1];
                // 结果图片名称
                String newFileName = sourceNamePre.substring(0, sourceNamePre.lastIndexOf("-")) + "-" + width + sourceNameSuf;

                // 将图片缩放为固定宽高100 px后，存储至目标Bucket。
                StringBuilder sbStyle = new StringBuilder();
                // 所用样式
                String styleType = "style/" + imgHandleStyle;

                Formatter styleFormatter = new Formatter(sbStyle);
                styleFormatter.format("%s|sys/saveas,o_%s,b_%s", styleType,
                        // 结果图片名称
                        BinaryUtil.toBase64String(newFileName.getBytes()),
                        // 保存的bucket
                        BinaryUtil.toBase64String(bucketName.getBytes()));
                System.out.println(sbStyle.toString());

                ProcessObjectRequest request = new ProcessObjectRequest(bucketName, sourceImage, sbStyle.toString());
                GenericResult processResult = ossClient.processObject(request);
                String json = null;
                try {
                    json = IOUtils.readStreamAsString(processResult.getResponse().getContent(), "UTF-8");
                    processResult.getResponse().getContent().close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                System.out.println(json);

                // 图片拷贝
                this.copyObject(ossClient, bucketName, newFileName, bucketName, uploadFilePath + newFileName);
                // 组装需要删除图片
                deleteObjectList.add(newFileName);
            }
            // 删除拷贝的源文件，完成文件移动
            this.deleteObjectList(ossClient, bucketName, deleteObjectList);
        }
    }

    /**
     * 拷贝文件
     *
     * @param ossClient
     * @param sourceBucketName      源文件bucket
     * @param sourceKey             源文件
     * @param destinationBucketName 目的地bucket
     * @param destinationKey        目的地文件
     */
    private void copyObject(OSS ossClient, String sourceBucketName, String sourceKey, String destinationBucketName, String destinationKey) {
        // 拷贝文件。
        CopyObjectResult result = ossClient.copyObject(sourceBucketName, sourceKey, destinationBucketName, destinationKey);
        System.out.println("{ObjectCopy}：ETag: " + result.getETag() + " LastModified: " + result.getLastModified());
    }

    /**
     * 批量删除文件
     *
     * @param ossClient
     * @param bucketName
     * @param deleteObjectList
     */
    private void deleteObjectList(OSS ossClient, String bucketName, ArrayList<String> deleteObjectList) {
        DeleteObjectsResult deleteObjectsResult = ossClient.deleteObjects(new DeleteObjectsRequest(bucketName).withKeys(deleteObjectList));
        List<String> deletedObjects = deleteObjectsResult.getDeletedObjects();
        System.out.println("{ObjectDelete}：Objects：" + deletedObjects);
    }

    private String getContentType(String FilenameExtension) {
        if (FilenameExtension.equalsIgnoreCase(".bmp")) {
            return "image/bmp";
        }
        if (FilenameExtension.equalsIgnoreCase(".gif")) {
            return "image/gif";
        }
        if (FilenameExtension.equalsIgnoreCase(".jpeg") ||
                FilenameExtension.equalsIgnoreCase(".jpg") ||
                FilenameExtension.equalsIgnoreCase(".png")) {
            return "image/jpeg";
        }
        if (FilenameExtension.equalsIgnoreCase(".html")) {
            return "text/html";
        }
        if (FilenameExtension.equalsIgnoreCase(".txt")) {
            return "text/plain";
        }
        if (FilenameExtension.equalsIgnoreCase(".vsd")) {
            return "application/vnd.visio";
        }
        if (FilenameExtension.equalsIgnoreCase(".pptx") ||
                FilenameExtension.equalsIgnoreCase(".ppt")) {
            return "application/vnd.ms-powerpoint";
        }
        if (FilenameExtension.equalsIgnoreCase(".docx") ||
                FilenameExtension.equalsIgnoreCase(".doc")) {
            return "application/msword";
        }
        if (FilenameExtension.equalsIgnoreCase(".xml")) {
            return "text/xml";
        }
        return "image/jpeg";
    }

    /**
     * 获取图片路径
     *
     * @param fileUrl
     * @return
     */
    private String getImgUrl(String fileUrl, String uploadFilePath) {
        if (StringUtils.isNotEmpty(fileUrl)) {
            String[] split = fileUrl.split("/");
            String url = this.getUrl(uploadFilePath + split[split.length - 1]);
//                log.info(url);
//                String[] spilt1 = url.split("\\?");
//                return spilt1[0];
            return url;
        }
        return "";
    }

    /**
     * 获得url链接
     *
     * @param key
     * @return
     */
    private String getUrl(String key) {
        // 设置URL过期时间为10年  3600l* 1000*24*365*10
//        Date expiration = new Date(new Date().getTime() + 3600l * 1000 * 24 * 365 * 10);
        // 设置URL过期时间为10分钟  1000l * 60 * 10
        Date expiration = new Date(new Date().getTime() + 1000l * 60 * 10);
//        Date expiration = new Date(new Date().getTime() + 1000l * 20);
        // 生成URL
        OSS ossClient = OssClientFactory.getOssClient();
        URL url = ossClient.generatePresignedUrl(bucketName, key, expiration);
        if (url != null) {
            return url.toString();
        }
        return null;
    }

//    /**
//     * 多图片上传
//     *
//     * @param fileList
//     * @return
//     */
//    public String checkList(List<MultipartFile> fileList, String uploadFilePath) {
//        String fileUrl = "";
//        String str = "";
//        String photoUrl = "";
//        for (int i = 0; i < fileList.size(); i++) {
//            fileUrl = uploadImg2Oss(fileList.get(i), uploadFilePath);
//            str = getImgUrl(fileUrl, uploadFilePath);
//            if (i == 0) {
//                photoUrl = str;
//            } else {
//                photoUrl += "," + str;
//            }
//        }
//        return photoUrl.trim();
//    }

//    /**
//     * 多图片路径获取
//     * 十分钟有效期
//     *
//     * @param fileList
//     * @return
//     */
//    public List<FileInfo> formatFilePath(List<FileInfo> fileList, String uploadFilePath) {
//        List<FileInfo> resultList = new ArrayList<>();
//        for (int i = 0; i < fileList.size(); i++) {
//            FileInfo fileInfo = fileList.get(i);
//            if (fileInfo.getRequestKey() == null) {
//                continue;
//            }
//            String filePath = getImgUrl(fileInfo.getRequestKey(), uploadFilePath);
//            fileInfo.setFilePath(filePath);
//            resultList.add(fileInfo);
//        }
//        return resultList;
//    }

    /**
     * 单个图片上传并生成四种图片处理结果并获取原图访问链接
     *
     * @param uploadFilePath 上传目录
     * @param fileName       作用域名称
     * @param uploadFileName 上传后的文件名
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public Map<String, String> uploadImgAndHandle(HttpServletRequest request, String uploadFilePath, String fileName, String uploadFileName) {
        MultipartHttpServletRequest mulReq = (MultipartHttpServletRequest) request;
        MultipartFile mulFile = mulReq.getFile(fileName);
        // 真实上传文件名
        String originalFilename = mulFile.getOriginalFilename();
        // 后缀名
        String extName = originalFilename.substring(originalFilename.lastIndexOf("."));
        // 上传oss并生成固定大小图片
        String requestKey = uploadImg2OssAndHandleImg(mulFile, uploadFilePath, uploadFileName);
//        String str = getImgUrl(requestKey, uploadFilePath);
        // 因为是公开读，所以直接访问即可，访问链接可以使用jmdf路径
//        String filePath = "https://" + bucketName + "." + uploadPre + "/" + uploadFilePath + uploadFileName + extName;
        String filePath = viewPre + "/" + uploadFilePath + uploadFileName + extName;

        Map<String, String> resultMap = new HashMap<>();
        resultMap.put("filePath", filePath);
        resultMap.put("requestKey", requestKey);
        return resultMap;
    }

    /**
     * 单个图片上传并获取原图访问链接
     *
     * @param uploadFilePath 上传目录
     * @param fileName       作用域名称
     * @param uploadFileName 上传后的文件名
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public Map<String, String> uploadImg(HttpServletRequest request, String uploadFilePath, String fileName, String uploadFileName) {
        MultipartHttpServletRequest mulReq = (MultipartHttpServletRequest) request;
        MultipartFile mulFile = mulReq.getFile(fileName);
        // 真实上传文件名
        String originalFilename = mulFile.getOriginalFilename();
        // 后缀名
        String extName = originalFilename.substring(originalFilename.lastIndexOf("."));
        // 上传oss
        String requestKey = uploadImg2Oss(mulFile, uploadFilePath, uploadFileName);
//        String str = getImgUrl(requestKey, uploadFilePath);
        // 因为是公开读，所以直接访问即可，访问链接可以使用jmdf路径
//        String filePath = "https://" + bucketName + "." + uploadPre + "/" + uploadFilePath + uploadFileName + extName;
        String filePath = viewPre + "/" + uploadFilePath + uploadFileName + extName;

        Map<String, String> resultMap = new HashMap<>();
        resultMap.put("filePath", filePath);
        resultMap.put("requestKey", requestKey);
        return resultMap;
    }
}
